package core

import (
	"errors"
	"github.com/shopspring/decimal"
	"qiuya/ast"
	"qiuya/util"
	"sync"
)

type Collection struct {
	DBName         string
	CollectionName string
	Mp             *CollectionMap
	RWLock         sync.RWMutex `json:"-"`
}

var ZERO = decimal.NewFromInt(int64(0))
var ONE = decimal.NewFromInt(int64(1))

func NewCollection(db, name string) *Collection {
	ins := &Collection{
		DBName:         db,
		CollectionName: name,
		Mp:             NewCollectionMap(),
	}
	return ins
}

//func insert(col *Collection, data map[string]interface{}) interface{}  {
//	id := uint64(snowflake.Generate())
//	data["_id"] = id
//	col.Mp.Put(id, data)
//	WriteLog(col.DBName, col.CollectionName, ACTION_INSERT, data)
//	return data
//}

func Insert(db, col string, data map[string]interface{}) (ret map[string]interface{}, err error) {
	res, err := InsertMany(db, col, []map[string]interface{}{data})
	if err != nil {
		return
	}
	if len(res) == 0 {
		err = errors.New("插入失败")
		return
	}
	ret = res[0]
	return
}

func InsertMany(db, col string, data []map[string]interface{}) (ret []map[string]interface{}, err error) {
	if data == nil {
		err = errors.New("无法插入空的对象")
		return
	}
	coll := GetCollection(db, col)
	coll.RWLock.Lock()
	defer coll.RWLock.Unlock()
	ret = []map[string]interface{}{}
	for _, v := range data {
		id, err := snowflake.NextId()
		if err != nil {
			return nil, err
		}
		v["_id"] = decimal.NewFromInt(id)
		coll.Mp.Put(id, v)
		ret = append(ret, v)
	}
	if len(ret) > 0 {
		WriteLog(coll.DBName, coll.CollectionName, ACTION_SET, ret)
	}

	return
}

func setMany(db, col string, _data interface{}) error {
	data, ok := _data.([]interface{})
	if !ok {
		return errors.New("failed to set many")
	}
	coll := GetCollection(db, col)
	coll.RWLock.Lock()
	defer coll.RWLock.Unlock()
	for _, v := range data {
		var mp = v.(map[string]interface{})
		switch mp["_id"].(type) {
		case string:
			var d, err = decimal.NewFromString(mp["_id"].(string))
			if err != nil {
				break
			}
			coll.Mp.Put(d.IntPart(), mp)
			break
		case decimal.Decimal:
			coll.Mp.Put(mp["_id"].(decimal.Decimal).IntPart(), mp)
			break
		}
	}
	return nil
}

func deleteByIds(db, co string, _ids interface{}) (err error) {
	ids, ok := _ids.([]interface{})
	if !ok {
		return errors.New("failed to delete by ids")
	}
	col := GetCollection(db, co)
	col.RWLock.Lock()
	defer col.RWLock.Unlock()
	for _, v := range ids {
		col.Mp.Delete((v.(decimal.Decimal).IntPart()))
	}
	return nil
}

func Replace(db, co string, _query map[string]interface{}, replacement map[string]interface{}) (success interface{}, err error) {
	col := GetCollection(db, co)
	col.RWLock.Lock()
	defer col.RWLock.Unlock()
	//Find
	return
}

func Delete(db, co string, query map[string]interface{}) (int, error) {
	col := GetCollection(db, co)
	col.RWLock.Lock()
	defer col.RWLock.Unlock()
	if query == nil {
		return 0, errors.New("必须指定一个删除条件")
	}
	i := 0
	for _ = range query {
		i++
	}
	if i == 0 {
		return 0, errors.New("必须指定一个删除条件")
	}
	ret, err := find(append([]map[string]interface{}{}, col.Mp.Values...), query)
	if err != nil {
		return 0, err
	}
	var ids []interface{}
	for _, v := range ret {
		id := v["_id"].(decimal.Decimal).IntPart()
		col.Mp.Delete(id)
		ids = append(ids, id)
	}
	WriteLog(db, co, ACTION_DELETE, ids)
	return len(ret), nil
}

func Count(db, co string, query map[string]interface{}) (int, error) {
	if query == nil {
		return 0, errors.New("查询条件错误")
	}
	items, err := Find(db, co, query)
	if err != nil {
		return 0, err
	}
	return len(items), nil
}

func Find(db, co string, query map[string]interface{}) ([]map[string]interface{}, error) {
	col := GetCollection(db, co)
	col.RWLock.RLock()
	defer col.RWLock.RUnlock()
	return find(append([]map[string]interface{}{}, col.Mp.Values...), query)
}

func find(source []map[string]interface{}, query map[string]interface{}) ([]map[string]interface{}, error) {
	node, err := ast.ParseQuery(query)
	if err != nil {
		return nil, err
	}
	if node == nil {
		return source, nil
	}
	var ret = []map[string]interface{}{}
	for _, v := range source {
		if ast.Match(node, v) {
			ret = append(ret, v)
		}
	}
	return ret, nil
}

func Aggregate(db, co string, query []map[string]interface{}) ([]map[string]interface{}, error) {
	//var query []interface{}
	//query, ok := _query.([]interface{})
	//if !ok {
	//	query = []interface{}{}
	//}
	col := GetCollection(db, co)
	col.RWLock.RLock()
	defer col.RWLock.RUnlock()
	var ret = append([]map[string]interface{}{}, col.Mp.Values...)
	var err error
	var hasCopy = false
	for _, single := range query {
		//if single, ok := v.(map[string]interface{}); ok {
		if match, ok := single["$match"].(map[string]interface{}); ok {
			ret, err = find(ret, match)
			if err != nil {
				return nil, err
			}
		} else if _group, ok := single["$group"].(map[string]interface{}); ok {
			ret = Group(ret, _group)
			//fmt.Println(_group)
		} else if skip, ok := single["$skip"].(decimal.Decimal); ok {
			if skip.IntPart() > int64(len(ret)) {
				ret = []map[string]interface{}{}
			} else {
				ret = ret[skip.IntPart():]
			}
		} else if limit, ok := single["$limit"].(decimal.Decimal); ok {
			if limit.IntPart() <= int64(len(ret)) {
				ret = ret[:limit.IntPart()]
			}
		} else if _project, ok := single["$project"].(map[string]interface{}); ok {
			mode := 0
			var items = map[string]bool{}
			for k, v := range _project {
				switch v.(type) {
				case decimal.Decimal:
					var d = v.(decimal.Decimal)
					if d.Equals(ONE) {
						if mode == -1 {
							return nil, errors.New("project中无法混合使用0和1")
						}
						mode = 1
					} else if d.Equals(ZERO) {
						if mode == 1 {
							return nil, errors.New("project中无法混合使用0和1")
						}
						mode = -1
					}
					items[k] = true
					break

				case string:
					//字段变换
					break
				}
			}
			if mode != 0 {
				var _ret = []map[string]interface{}{}
				for _, v := range ret {
					var mp = map[string]interface{}{}
					if mode == 1 {
						//只保留
						for item, _ := range items {
							mp[item] = v[item]
						}
					} else {
						//只排除
						for kk, vv := range v {
							if _, ok := items[kk]; !ok {
								mp[kk] = vv
							}
						}
					}
					_ret = append(_ret, mp)
				}
				ret = _ret
			}
		} else if _sort, ok := single["$sort"].([]interface{}); ok {
			quickSortRecursive(ret, 0, len(ret)-1, _sort)
		} else if _lookup, ok := single["$lookup"].(map[string]interface{}); ok {
			err = lookup(db, &ret, _lookup, &hasCopy)
			if err != nil {
				return nil, err
			}
		} else if _graphLookup, ok := single["$graphLookup"].(map[string]interface{}); ok {
			err = graphLookup(db, &ret, _graphLookup, &hasCopy)
			if err != nil {
				return nil, err
			}
		}
		//}
	}
	return ret, nil
}

func sortSingleItem(_a, _b interface{}, sortOption []interface{}) int {
	for _, _v := range sortOption {
		var v, ok = _v.(decimal.Decimal)
		if !ok {
			continue
		}
		if v.Equals(ONE) {
			r, _ := util.Compare(_b, _a)
			//倒叙
			if r == 0 {
				continue
			} else {
				return r
			}
		} else {
			//正序
			r, _ := util.Compare(_a, _b)
			if r == 0 {
				continue
			} else {
				return r
			}
		}
	}

	return 0
}

/**
快速排序
*/
func quickSortRecursive(arr []map[string]interface{}, start int, end int, sortOption []interface{}) {
	if start >= end {
		return
	}
	k := arr[end]
	left := start
	right := end - 1
	for left < right {
		for sortSingleItem(arr[left], k, sortOption) < 0 && left < right {
			left++
		}
		for sortSingleItem(arr[right], k, sortOption) >= 0 && left < right {
			right--
		}
		arr[left], arr[right] = arr[right], arr[left]
	}
	if sortSingleItem(arr[left], arr[end], sortOption) < 0 {
		left++
	}
	arr[left], arr[end] = k, arr[left]
	quickSortRecursive(arr, start, left-1, sortOption)
	quickSortRecursive(arr, left+1, end, sortOption)
}

func Update(db, co string, query map[string]interface{}, action map[string]interface{}, upsert bool) (int, error) {
	if query == nil {
		return 0, errors.New("查询条件不能为空")
	}
	if action == nil {
		return 0, errors.New("更新行为不能为空")
	}
	col := GetCollection(db, co)
	col.RWLock.Lock()
	defer col.RWLock.Unlock()
	res, err := find(append([]map[string]interface{}{}, col.Mp.Values...), query)
	if err != nil {
		return 0, err
	}
	//get set
	set, ok := action["$set"].(map[string]interface{})
	//todo: 后续需要先拷贝再进行赋值，然后重新写回，可以避免一些需要中断操作的错误
	if ok {
		//如果为空，且upsert为true，则新插入
		if len(res) == 0 && upsert {
			id, err := snowflake.NextId()
			if err != nil {
				return 0, err
			}
			set["_id"] = decimal.NewFromInt(id)
			col.Mp.Put(id, set)
			res = append(res, set)
		} else {
			for _, v := range res {
				for kk, vv := range set {
					//_id无法更新
					if kk == "_id" {
						continue
					}
					v[kk] = vv
				}
			}
		}
	}
	WriteLog(db, co, ACTION_SET, res)
	return len(res), nil
}

func ShowDBs() []string {
	var mp = map[string]bool{}
	globalMutex.RLock()
	defer globalMutex.RUnlock()
	for _, v := range qiuya.Collections.Values {
		mp[v.DBName] = true
	}
	var ret []string
	for k, _ := range mp {
		ret = append(ret, k)
	}
	return ret
}

func ShowCols(db string) []string {
	var mp = map[string]bool{}
	globalMutex.RLock()
	defer globalMutex.RUnlock()
	for _, v := range qiuya.Collections.Values {
		if v.DBName == db {
			mp[v.CollectionName] = true
		}
	}
	var ret []string
	for k, _ := range mp {
		ret = append(ret, k)
	}
	return ret
}
